/*
 * Tezad - Classic puzzle game
 * Copyright 2009 Shayne Riley and Paul Maseberg
 *
 * Tezad is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Tezad is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Tezad.  If not, see <http://www.gnu.org/licenses/>
 * or write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * To contact the authors on questions or issues regarding the license,
 * you may send an email to <pezads at gmail dot com>
 */

#include "GameMinoStruct.h"

#include <stdexcept>

GameMinoStruct::GameMinoStruct(int bricksRows[], int bricksCols[],
        int inBrickStyle)
: mBrickStyle(inBrickStyle)
{
    for (int i = 0; i < 16; ++i)
    {
        mBricksRows[i] = bricksRows[i];
        mBricksCols[i] = bricksCols[i];
    }
}

GameMinoStruct::GameMinoStruct() { /* Empty. Stinking arrays. */ }

GameMinoStruct::~GameMinoStruct() { /* Empty */ }

void GameMinoStruct::bricks(const GameMinoState& inState,
        int outRows[], int outCols[]) const
{
    int orientOff = inState.orientation() * 4;
    int rowOff = inState.row();
    int colOff = inState.col();
    for (int brick = 0; brick < 4; ++brick)
    {
        outRows[brick] = mBricksRows[brick + orientOff] + rowOff;
        outCols[brick] = mBricksCols[brick + orientOff] + colOff;
    }
}

int GameMinoStruct::brickStyle() const
{
    return mBrickStyle;
}

// Thanks to a lack of namespaces, this mino function is out there.
const GameMinoStruct& GameMinoStruct::mino(int minoNum)
{
    // These are distances away from the origin.
    // br stands for brick rows, bc stands for brick columns.
    // elements 0-3 are for 1st orientation, 4-7 2nd, 8-12 3rd, and 13-15 4th.
    // Positive is upwards for rows, left for columns.

    static int ibr[16] =
    {
             +0,  0,  0,  0,
             +1,  0, -1, -2,
             +1,  1,  1,  1, // This is an odd ball. It's not on an origin!
             +1,  0, -1, -2
    };
    static int ibc[16] =
    {
            -1,  0,  1,  2,
            +1,  1,  1,  1, // This is an odd ball. It's not on an origin!
            -1,  0,  1,  2,
            +0,  0,  0,  0
    };

    static int jbr[16] =
    {
            +1,  0,  0,  0,
            +1,  1,  0, -1,
            +0,  0,  0, -1,
            +1,  0, -1, -1
    };
    static int jbc[16] =
    {
            -1, -1,  0,  1,
            +0,  1,  0,  0,
            -1,  0,  1,  1,
            +0,  0, -1,  0
    };

    static int lbr[16] =
    {
            +1,  0,  0,  0,
            +1,  0, -1, -1,
            +0,  0,  0, -1,
            +1,  1,  0, -1
    };
    static int lbc[16] =
    {
            +1, -1,  0,  1,
            +0,  0,  0,  1,
            -1,  0,  1, -1,
            -1,  0,  0,  0
    };

    static int obr[16] =
    {
            +1,  1,  0,  0,
            +1,  1,  0,  0,
            +1,  1,  0,  0,
            +1,  1,  0,  0
    };
    static int obc[16] =
    {
            +0,  1,  0,  1,
            +0,  1,  0,  1,
            +0,  1,  0,  1,
            +0,  1,  0,  1,
    };

    static int sbr[16] =
    {
            +1,  1,  0,  0,
            +1,  0,  0, -1,
            +0, +0, -1, -1,
            +1,  0,  0, -1
    };
    static int sbc[16] =
    {
            +0,  1, -1,  0,
            +0,  0,  1,  1,
            +0,  1, -1,  0,
            -1, -1,  0,  0
    };

    static int tbr[16] =
    {
            +1,  0,  0,  0,
            +1,  0,  0, -1,
            +0,  0,  0, -1,
            +1,  0,  0, -1
    };
    static int tbc[16] =
    {
            +0, -1,  0,  1,
            +0,  0,  1,  0,
            -1,  0,  1,  0,
            +0, -1,  0,  0
    };

    static int zbr[16] =
    {
            +1, +1,  0,  0,
            +1,  0,  0, -1,
            +0,  0, -1, -1,
            +1,  0,  0, -1
    };
    static int zbc[16] =
    {
            -1,  0,  0,  1,
            +1,  0,  1,  0,
            -1,  0,  0,  1,
            +0, -1,  0, -1
    };

    static GameMinoStruct structs[7] =
    {
            GameMinoStruct(ibr, ibc, 1),
            GameMinoStruct(jbr, jbc, 2),
            GameMinoStruct(lbr, lbc, 3),
            GameMinoStruct(obr, obc, 4),
            GameMinoStruct(sbr, sbc, 5),
            GameMinoStruct(tbr, tbc, 6),
            GameMinoStruct(zbr, zbc, 7)
    };

    if (minoNum < 0 || minoNum > 6)
    {
        throw std::out_of_range("minoNum must be between 0 and 6, inclusive.");
    }

    return structs[minoNum];
}
